
# ******************************************************
# * Copyright © 2016-2023 - Jordan Irwin (AntumDeluge) *
# ******************************************************
# * This software is licensed under the MIT license.   *
# * See: LICENSE.txt for details.                      *
# ******************************************************

## Defines tooltips that have longer texts.
#
#  @module globals.tooltips

import wx

import globals.execute

from dbr.language      import GT
from dbr.templates     import local_templates_path
from globals.changes   import section_delims
from libdbr.logger     import Logger
from libdebreate.ident import btnid
from libdebreate.ident import pgid
from ui.helper         import FieldEnabled


_logger = Logger(__name__)

# *** wizard buttons *** #
TT_wiz_prev = wx.ToolTip(GT("上一页"))
TT_wiz_next = wx.ToolTip(GT("下一页"))

TT_control = {
  "btn browse": GT("打开预格式化好的文本"),
  "btn save": GT("保存信息到文本"),
  "btn preview": GT("预览文件"),
  "package": GT("包/软件名"),
  "version": GT("包/软件 发布版本"),
  "maintainer": GT("包/软件 维护者全名"),
  "email": GT("包/软件 维护者电子邮件地址"),
  "architecture": (
    GT("软件/包运行在那个平台"), "",
    GT("all = 平台不相关"),
    ),
  "section": GT("类别，包管理者依据分类对这个包进行分类"),
  "priority": GT("这个包升级的紧迫性"),
  "synopsis": GT("一行描述文本"),
  "description": (
    GT("更多详细的描述"), "",
    GT("这里可以使用多行描述文本,但是太长了lintian将会抱怨")
    ),
  "source": GT("上游源包名 "),
  "homepage": GT("上游源主页网址"),
  "essential": GT("为了(保证)系统的稳定，该包是否是必须的"),
}

TT_depends = {
  "btn browse": TT_control["btn browse"],
  "btn save": TT_control["btn save"],
  "btn preview": TT_control["btn preview"],
  "package": GT("依赖/冲突的包名"),
  "operator": GT("操作符"),
  "version": GT("和包名以及操作符相匹配的版本"),
  "depends": GT("将需要被安装的包(依赖包)"),
  "pre-depends": GT("将需要被安装和先行设置的包"),
  "recommends": GT("被强烈推荐并且将会默认安装的包"),
  "suggests": GT("可能有用但是不是特别必须且将会默认安装的包"),
  "enhances": GT("这个包可能会对增强包（的功能）有作用"),
  "conflicts": GT("如果已经被安装将被卸载的包"),
  "replaces": GT("包或者它的文件将被覆盖"),
  "breaks": GT("包冲突且将会被破坏配置"),
  "btn add": GT("添加依赖包到列表"),
  "btn append": GT("向列表里到一个选择好的依赖包添加可选择项"),
  "btn remove": GT("从列表里移除选择好的依赖包"),
  "btn clear": GT("清除依赖包列表"),
  "list": GT("将要被添加的依赖"),
}

TT_files = {
  "individually": GT("选中目录中的文件将被逐个添加到列表中"),
  "btn add": GT("添加选中的文件/文件夹到列表"),
  "btn remove": GT("从列表中删除选中的文件"),
  "btn clear": GT("清除文件列表"),
  "btn browse": GT("浏览目标安装目录"),
  "btn refresh": GT("更新文件\' 可执行状态 & 可用性"),
  "target": GT("文件的目标安装目录"),
  "filelist": (
      GT("文件将被添加到包和他们的目标目录"), "",
      GT("蓝色的字体 = 目录"),
      GT("红色字体 = 可执行"),
      GT("红色的背景 = 丢失文件/文件夹"),
      )
}

TT_manpages = {
  "add": GT("Add manpage"),
}

TT_scripts = {
  "preinst": GT("包安装前运行的脚本"),
  "postinst": GT("包安装后运行的脚本"),
  "prerm": GT("包卸载前运行脚本"),
  "postrm": GT("包卸载后运行脚本"),
  "script body": GT("Script text body"),
  "target": GT("脚本创建快捷方式的目录"),
  "al list": GT("文件列表中被链接的可运行文件"),
  "btn import": GT("导入从文件页面标记的可运行文件"),
  "btn remove": GT("从列表中移除选择的可运行文件"),
  "btn build": GT("生成脚本"),
  "btn help": GT("如何使用快速链接"),
}

TT_changelog = {
  "package": TT_control["package"],
  "version": TT_control["version"],
  "dist": (
    GT("Debian/Ubuntu等目标发行版的名称"), "",
    GT("可以通过 ‘选项 ➜ 更新发行版命名缓存’ 来更新此列表.")
    ),
  "urgency": TT_control["priority"],
  "maintainer": TT_control["maintainer"],
  "email": TT_control["email"],
  "changes": (
    GT("List new changes here, separated one per line"), "",
    GT("The first line will be prepended with an asterix (*) automatically. To denote any other sections, put one of the following as the first character on the line:"),
    "\t{}".format(",  ".join(list(section_delims))),
    ),
  "target default": GT("安装更新日志的标准目录"),
  "target custom": GT("安装更新日志的定制目录"),
  "btn import": GT("从Control页面导入信息"),
  "btn add": GT("在更新之上追加一个新的日志内容(log entry)"),
  "indent": GT("不要删去规律的行的前置空格"),
  "log": GT("格式化的更新日志内容(可编辑的)"),
}

no_lic_templates = GT("No license templates available")
TT_copyright = {
  "list_disabled": no_lic_templates,
  "full": (
    GT("Full Template"), "",
    GT("复制系统,应用,或者本地的一个 license"),
    GT("系统:"), "\t{}".format(GT("拷贝文本来自于存储于以下位置的 许可证书")),
    "\t/usr/share/common-licenses",
    GT("应用:"), "\t{}".format(GT("拷贝一个使用Debreate发布的标准")),
    GT("本地:"), "\t{}".format(GT("拷贝一个来自于以下位置的用户定义标准")),
    "\t{}".format(local_templates_path),
    ),
  "full_disabled": no_lic_templates,
  "short": (
    GT("Short Template"), "",
    GT("创建一个版权许可头& 简短地指向一个标准系统许可证书，证书来自于以下位置"),
    ),
  "short_disabled": no_lic_templates,
}

TT_menu = {
  "open": GT("从文件导入启动器"),
  "export": GT("到处启动器到文本文件"),
  "preview": GT("预览启动器文本"),
  "filename": GT("定制的文件名用来做启动器"),
  "filename chk": GT("除非选中, filename 的值将被用作启动器的输出文件名"),
  "name": GT("启动器上显示的名称"),
  "exec": GT("启动的可执行程序"),
  "comment": GT("光标悬停在启动器上显示的文字"),
  "icon": GT("启动器显示的图标"),
  "type": (
    GT("启动器类型"), "",
    GT("Application:"), "\t{}".format(GT("应用程序的快捷方式")),
    GT("Link:"), "\t{}".format(GT("web URL的快捷方式")),
    GT("Directory:"), "\t{}".format(GT("包含元数据和菜单项的容器")),
    ),
  "terminal": GT("表明应用是否运行在一个终端中"),
  "startupnotify": GT("启动时在系统面板显示一个通知"),
  "encoding": GT("设置启动器被用来读取的编码"),
  "category": GT("分类决定了启动气在系统菜单项中的位置"),
  "add category": GT("添加当前的分类到列表"),
  "rm category": GT("移除列表中选中的分类"),
  "clear categories": GT("清除分类列表"),
  "categories": GT("分类决定了启动器在系统菜单项中的位置"),
  "no disp": GT("This options means \"This application exists, but don't display it in the menus\""),
  "show in": GT("只有当选项满足时启动器才会显示"),
  "other": (
    GT("除了以上可使用项目外混杂项目的领域"), "",
    GT('点击 "帮助 ➜ 链接 ➜ 启动器 / 桌面快捷方式" 获得更多可用选项'), "",
    GT("Warning:"),
    "\t{}".format(GT("格式不正确的文本可能会导致启动器不可用")),
    )
}

TT_build = {
  "md5": GT("为包内所有组织好的文件创建一个校验和"),
  "md5_disabled": GT("使用此选项需要安装md5sum包"),
  "permiss": GT("Ensure files & directories use standard permissions"),
  "strip": (
    GT("从二进制文件中丢弃无用的修改"), "",
    GT("See \"man 1 strip\""),
    ),
  "strip_disabled": GT("使用此选项需要安装binutils包"),
  "rmstage": GT("包创建好后删除组织好的目录树"),
  "lintian": (
    GT("通过lintian的规定检查包的警告和错误"), "",
    GT('了解更多点击 "帮助 ➜ 链接 ➜ Lintian具体描述"'),
    ),
  "lintian_disabled": GT("使用此选项需要安装lintian包"),
  btnid.BUILD: GT("开始构建"),
  "install": (
    GT("构建完毕后使用系统安装器安装包"), "",
    "{} {}".format(GT("系统安装器请关注:"), globals.execute.getDebInstaller()),
    ),
  "install_disabled": (
    GT("使用此选项需要安装以下包中的一个:"), "",
    GT("gdebi-gtk, gdebi-kde"),
    ),
}


TT_pages = {
  pgid.CONTROL: TT_control,
  pgid.DEPENDS: TT_depends,
  pgid.FILES: TT_files,
  pgid.MAN: TT_manpages,
  pgid.SCRIPTS: TT_scripts,
  pgid.CHANGELOG: TT_changelog,
  pgid.COPYRIGHT: TT_copyright,
  pgid.MENU: TT_menu,
  pgid.BUILD: TT_build,
}


## Universal function for setting window/control tooltips.
def SetToolTip(tooltip, control, required=False):
  if isinstance(tooltip, wx.ToolTip):
    tooltip = tooltip.GetTip()
  elif isinstance(tooltip, (tuple, list)):
    tooltip = "\n".join(tooltip)

  if tooltip:
    if required:
      tooltip = "{}\n\n{}".format(tooltip, GT("Required"))
    register(control, tooltip)


## Sets multiple tooltips at once.
def SetToolTips(tooltip, control_list, required=False):
  for FIELD in control_list:
    SetToolTip(tooltip, FIELD, required)


## @todo Doxygen
def SetPageToolTips(parent, page_id=None):
  control_list = []

  if not page_id:
    page_id = parent.GetId()

  # recursively set tooltips for children
  for FIELD in parent.GetChildren():
    control_list.append(FIELD)

    sub_children = FIELD.GetChildren()
    if sub_children:
      SetPageToolTips(FIELD, page_id)

  if page_id in TT_pages:
    for FIELD in control_list:
      tooltip = None

      # use ID first
      field_id = FIELD.GetId()
      if field_id in TT_pages[page_id]:
        tooltip = TT_pages[page_id][field_id]

      else:
        try:
          name = str(FIELD.tt_name).lower()

        except AttributeError:
          try:
            name = FIELD.GetName().lower()

          except AttributeError:
            _logger.warn("Object has no name, not setting tooltip: {}".format(type(FIELD)))

            continue

        required = False
        if name:
          if "*" in name[-2:]:
            required = True

          # the » character causes a different tooltip to be set for disabled fields
          if "»" in name[-2:] and not FieldEnabled(FIELD):
            name = "{}_disabled".format(name)

          name = name.replace("*", "")
          name = name.replace("»", "")

        if name in TT_pages[page_id]:
          tooltip = TT_pages[page_id][name]

      if tooltip:
        SetToolTip(tooltip, FIELD, required)


__registry = {}
__enabled = False

## Registers a tooltip associated with a window.
#
#  @param window
#    `wx.Window` instance.
#  @param tt
#    Text to display for tooltip.
def register(window, tt):
  if isinstance(tt, wx.ToolTip):
    tt = tt.GetTip()
  __registry[window] = tt
  if __enabled:
    window.SetToolTip(wx.ToolTip(tt))

## Unregisters a window's tooltip.
#
#  @param window
#    `wx.Window` instance to be unregistered.
def unregister(window):
  if window in __registry:
    del __registry[window]

## Enables or disables tooltips globally.
#
#  @param enabled
#    Flag dertimining if tooltips should be enabled or disabled.
def enable(enabled=True):
  global __enabled
  __enabled = enabled
  wx.ToolTip.Enable(enabled)
  if __checkEnabled() == enabled:
    return True
  # fallback to manually setting
  _logger.debug("registered tooltips: {}".format(len(__registry)))
  for window in tuple(__registry):
    if not window:
      _logger.debug("element deleted: {}".format(window))
      del __registry[window]
      continue
    if enabled:
      window.SetToolTip(wx.ToolTip(__registry[window]))
    else:
      window.UnsetToolTip()
  _logger.debug("tooltip state 'enabled={}' set manually".format(enabled))
  return __checkEnabled() == enabled

## Gets the cached state.
#
#  @return
#    `True` if state is enabled.
def areEnabled():
  return __enabled

## Checks registered windows for enabled tooltips.
#
#  Note: Requires at least one tooltip to be registered.
#
#  @return
#    `True` if global tooltips are recognized as enabled.
def __checkEnabled():
  for window in tuple(__registry):
    if not window:
      _logger.debug("element deleted: {}".format(window))
      del __registry[window]
      continue
    if window.GetToolTip() != None:
      return True
  return False
